﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Text;
using Foothill.Common;
using Foothill.Common.Logging;
using Foothill.DataAccess.Interface;
using Foothill.Model;

namespace Foothill.DataAccess.Repository
{
    public class AdSearchRepo : DbAccessBase, IAdSearchRepo
    {
        // get the complete result set, not paged
        public IList<ForSaleAd> AdvancedSearchGetAllResult(ForSaleAdAdvancedSearchParameter searchParam)
        {
            string sql = AdSearchRepoSqlGenerator.ConstructAdvancedSearchQuery(searchParam);
            DbCommand dbCommand = FoothillDB.GetSqlStringCommand(sql);

            // add query parameters
            AddQueryParameters(dbCommand, searchParam);

            IList<ForSaleAd> result = new List<ForSaleAd>();
            ForSaleAd post = null;

            try
            {
                using (IDataReader reader = FoothillDB.ExecuteReader(dbCommand))
                {
                    while (reader.Read())
                    {
                        post = ConstructForSaleAdInstance(reader);
                        result.Add(post);
                    }
                }
            }
            catch (Exception exception)
            {
                Log.Error(FoothillModule.DataAccess, exception.Message, exception);
                throw new DataAccessException("Error in advanced search", exception);
            }

            return result;
        }

        public IList<ForSaleAd> SearchByIdList(IList<int> idList)
        {
            IList<ForSaleAd> resultSet = new List<ForSaleAd>();

            if (!idList.Any())
            {
                return resultSet;
            }
            
            string sql = AdSearchRepoSqlGenerator.ConstructGetByAdIdListSql(idList);
            DbCommand dbCommand = FoothillDB.GetSqlStringCommand(sql);

            int count = idList.Count;
            for (int i = 0; i < count; ++i)
            {
                FoothillDB.AddInParameter(dbCommand, string.Format("postId{0}", i), DbType.Int32, idList[i]);
            }

            ForSaleAd post;
            try
            {
                using (IDataReader reader = FoothillDB.ExecuteReader(dbCommand))
                {
                    while (reader.Read())
                    {
                        post = ConstructForSaleAdInstance(reader);
                        resultSet.Add(post);
                    }
                }
            }
            catch (Exception exception)
            {
                Log.Error(FoothillModule.DataAccess, exception.Message, exception);
                throw new DataAccessException("Error in SearchByIdList", exception);
            }

            return resultSet;
        }

        // add query parameters for AdvancedSearch with filter
        private void AddQueryParameters(DbCommand dbCommand, ForSaleAdAdvancedSearchParameter searchParam)
        {
            RangeBasedAdSearchCriteria criteria;

            // year
            if (searchParam.TryGetRangeBasedCriteria(RangeBasedCriteria.YearMade, out criteria))
            {
                FoothillDB.AddInParameter(dbCommand, "YearFrom", DbType.Int32, criteria.Min);
                FoothillDB.AddInParameter(dbCommand, "YearTo", DbType.Int32, criteria.Max);
            }

            // kilometers
            if (searchParam.TryGetRangeBasedCriteria(RangeBasedCriteria.Kilometer, out criteria))
            {
                FoothillDB.AddInParameter(dbCommand, "KiloFrom", DbType.Int32, criteria.Min);
                FoothillDB.AddInParameter(dbCommand, "KiloTo", DbType.Int32, criteria.Max);
            }

            // price
            if (searchParam.TryGetRangeBasedCriteria(RangeBasedCriteria.Price, out criteria))
            {
                FoothillDB.AddInParameter(dbCommand, "PriceFrom", DbType.Int32, criteria.Min);
                FoothillDB.AddInParameter(dbCommand, "PriceTo", DbType.Int32, criteria.Max);
            }

            // vehicle condition
            if (searchParam.ConditionId != (int)VehicleCondition.Both)
            {
                FoothillDB.AddInParameter(dbCommand, "ConditionId", DbType.Int32, searchParam.ConditionId);
            }

            // transmission
            if (searchParam.TransmissionTypeId != (int)TransmissionType.Both)
            {
                FoothillDB.AddInParameter(dbCommand, "TransmissionTypeId", DbType.Int32, searchParam.TransmissionTypeId);
            }

            // listing type
            if (searchParam.ListingTypeId != (int)ListingTypes.Both)
            {
                FoothillDB.AddInParameter(dbCommand, "ListingTypeId", DbType.Int32, searchParam.ListingTypeId);
            }

            // location list
            if (!searchParam.AllLocationSelected)
            {
                for (int i = 0; i < searchParam.LocationIdList.Count; ++i)
                {
                    FoothillDB.AddInParameter(dbCommand, string.Format("location{0}", i), DbType.Int32, searchParam.LocationIdList[i]);
                }
            }

            // make and model
            if (!searchParam.IncludeAllMakes)
            {
                IList<int> modelIdList;
                IList<int> makeIdList;

                searchParam.GetSelectedMakeAndModelIdList(out makeIdList, out modelIdList);

                for (int i = 0; i < makeIdList.Count; ++i)
                {
                    FoothillDB.AddInParameter(dbCommand, string.Format("make{0}", i), DbType.Int32, makeIdList[i]);
                }

                for (int i = 0; i < modelIdList.Count; ++i)
                {
                    FoothillDB.AddInParameter(dbCommand, string.Format("model{0}", i), DbType.Int32, modelIdList[i]);
                }
            }
        }

        // construct a for-sale ad post instance
        private ForSaleAd ConstructForSaleAdInstance(IDataReader reader)
        {
            ForSaleAd instance = new ForSaleAd();

            instance.AdId = Convert.ToInt32(reader["AdId"]);
            instance.ModelId = Convert.ToInt32(reader["ModelId"]);
            instance.MakeId = Convert.ToInt32(reader["MakeId"]);
            instance.TransmissionTypeId = GetDbInt32(reader["TransmissionTypeId"], (int)TransmissionType.NA);
            instance.TransmissionTypeName = GetDbString(reader["TransmissionTypeName"], "");
            instance.YearMade = GetDbInt32(reader["YearMade"], DateTime.Now.Year);
            instance.Price = GetDbInt32(reader["Price"], 0);
            instance.MileAge = GetDbInt32(reader["MileAge"], 0);
            instance.Description = GetDbString(reader["Description"], "");
            instance.TimePosted = Convert.ToDateTime(reader["TimePosted"]);
            instance.ContactPhone = GetDbString(reader["ContactPhone"], "");
            instance.ContactEmail = GetDbString(reader["ContactEmail"], "");
            instance.EditKey = GetDbString(reader["EditKey"], "");
            instance.CityId = GetDbInt32(reader["CityId"], 0);
            instance.StatusId = GetDbInt32(reader["StatusId"], 0);
            instance.LastEditTime = Convert.ToDateTime(reader["LastEditTime"]);
            instance.ModelName = GetDbString(reader["ModelName"], "");
            instance.MakeName = GetDbString(reader["MakeName"], "");
            instance.CityName = GetDbString(reader["CityName"], "");
            instance.ProfilePhotoPath = GetDbString(reader["ProfilePhotoPath"], "");
            instance.VehicleConditionName = GetDbString(reader["VehicleConditionName"], "");
            instance.ListingTypeId = GetDbInt32(reader["ListingTypeId"], 0);
            instance.ListingTypeString = GetDbString(reader["ListingTypeName"], string.Empty);
            instance.PostedByUserAccountId = GetDbInt32(reader["PostedByUserAccountId"], 0);
            instance.NumClickedOn = GetDbInt32(reader["NumClickedOn"], 0);
            instance.PostedUserLogoFilePath = GetDbString(reader["UserLogoFilePath"], string.Empty);
            
            return instance;
        }
    }
}
